<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  

  
  <title>youngboy的个人blog</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta property="og:type" content="website">
<meta property="og:title" content="youngboy的个人blog">
<meta property="og:url" content="http://www.youngboy.vip/index.html">
<meta property="og:site_name" content="youngboy的个人blog">
<meta property="og:locale" content="default">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="youngboy的个人blog">
  
    <link rel="alternate" href="./atom.xml" title="youngboy的个人blog" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  
    <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  
  <link rel="stylesheet" href="./css/style.css">
</head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="./" id="logo">youngboy的个人blog</a>
      </h1>
      
        <h2 id="subtitle-wrap">
          <a href="./" id="subtitle">blog</a>
        </h2>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="./">Home</a>
        
          <a class="main-nav-link" href="./archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="./atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://www.youngboy.vip"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main">
  
    <article id="post-Spring Security ACL" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="./2018/12/23/Spring Security ACL/" class="article-date">
  <time datetime="2018-12-23T10:48:46.666Z" itemprop="datePublished">2018-12-23</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="./2018/12/23/Spring Security ACL/">Spring Security ACL</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h1 id="Spring-Security-ACL"><a href="#Spring-Security-ACL" class="headerlink" title="Spring Security ACL"></a>Spring Security ACL</h1><p><strong>目录</strong></p>
<ul>
<li>准备工作</li>
<li>表功能介绍</li>
<li>表acl_sid</li>
<li>表acl_class</li>
<li>表acl_object_identity</li>
<li>表acl_entry</li>
<li>Acl主要接口</li>
<li>配置AclService</li>
<li>配置DataSource</li>
<li>配置LookupStrategy</li>
<li>配置AclAuthorizationStrategy</li>
<li>配置grantingStrategy</li>
<li>配置AclCache</li>
<li>使用AclService</li>
<li>创建Acl</li>
<li>查找Acl</li>
<li>更新Acl</li>
<li>删除Acl</li>
<li>注入到AclPermissionEvaluator</li>
</ul>
<p>Acl的全称是<code>Access Control List</code>，俗称访问控制列表，是用以控制对象的访问权限的。其主要思想是将某个对象的某种权限授予给某个用户，或某种<code>GrantedAuthority</code>（可以简单的理解为某种角色），它们之间的关系都是多对多。如果某一个对象的某一操作是受保护的，那么在对该对象进行某种操作时就需要有对应的权限。</p>
<h2 id="1-1-准备工作"><a href="#1-1-准备工作" class="headerlink" title="1.1 准备工作"></a>1.1 准备工作</h2><p>使用Spring Security的Acl功能需要引入Acl相关的jar包。如果我们的应用是使用Maven构建的，则可以在应用的pom.xml文件中加入如下依赖。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">   &lt;dependency&gt;</span><br><span class="line"></span><br><span class="line">      &lt;groupId&gt;org.springframework.security&lt;/groupId&gt;</span><br><span class="line"></span><br><span class="line">      &lt;artifactId&gt;spring-security-acl&lt;/artifactId&gt;</span><br><span class="line"></span><br><span class="line">      &lt;version&gt;$&#123;spring.security.version&#125;&lt;/version&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/dependency&gt;</span><br></pre></td></tr></table></figure>
<p>此外，使用Spring Security的Acl时需要在数据库中建立四张表。在其官方文档中给出了一个基于数据库HSQLDB的建表语句（jar包中有包含sql文件）。其脚本如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">create table acl_sid (</span><br><span class="line"></span><br><span class="line">  id bigint generated by default as identity(start with 100) not null primary key,</span><br><span class="line"></span><br><span class="line">  principal boolean not null,</span><br><span class="line"></span><br><span class="line">  sid varchar_ignorecase(100) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_1 unique(sid,principal) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_class (</span><br><span class="line"></span><br><span class="line">  id bigint generated by default as identity(start with 100) not null primary key,</span><br><span class="line"></span><br><span class="line">  class varchar_ignorecase(100) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_2 unique(class) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_object_identity (</span><br><span class="line"></span><br><span class="line">  id bigint generated by default as identity(start with 100) not null primary key,</span><br><span class="line"></span><br><span class="line">  object_id_class bigint not null,</span><br><span class="line"></span><br><span class="line">  object_id_identity bigint not null,</span><br><span class="line"></span><br><span class="line">  parent_object bigint,</span><br><span class="line"></span><br><span class="line">  owner_sid bigint not null,</span><br><span class="line"></span><br><span class="line">  entries_inheriting boolean not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_3 unique(object_id_class,object_id_identity),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_1 foreign key(parent_object)references acl_object_identity(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_entry (</span><br><span class="line"></span><br><span class="line">  id bigint generated by default as identity(start with 100) not null primary key,</span><br><span class="line"></span><br><span class="line">  acl_object_identity bigint not null,ace_order int not null,sid bigint not null,</span><br><span class="line"></span><br><span class="line">  mask integer not null,granting boolean not null,audit_success boolean not null,</span><br><span class="line"></span><br><span class="line">  audit_failure boolean not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_4 unique(acl_object_identity,ace_order),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_4 foreign key(acl_object_identity)</span><br><span class="line"></span><br><span class="line">      references acl_object_identity(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_5 foreign key(sid) references acl_sid(id) );</span><br></pre></td></tr></table></figure>
<p>笔者使用的是Oracle数据库，其中没有boolean和主键自增功能，对于boolean类型都使用一位number表示。具体建表语句如下所示：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line">create table acl_sid (</span><br><span class="line"></span><br><span class="line">  id number not null primary key,</span><br><span class="line"></span><br><span class="line">  principal number(1) not null,</span><br><span class="line"></span><br><span class="line">  sid varchar(100) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_1 unique(sid,principal) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_class (</span><br><span class="line"></span><br><span class="line">  id number not null primary key,</span><br><span class="line"></span><br><span class="line">  class varchar(100) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_2 unique(class) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_object_identity (</span><br><span class="line"></span><br><span class="line">  id number not null primary key,</span><br><span class="line"></span><br><span class="line">  object_id_class number not null,</span><br><span class="line"></span><br><span class="line">  object_id_identity number not null,</span><br><span class="line"></span><br><span class="line">  parent_object number,</span><br><span class="line"></span><br><span class="line">  owner_sid number not null,</span><br><span class="line"></span><br><span class="line">  entries_inheriting number(1) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_3 unique(object_id_class,object_id_identity),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_1 foreign key(parent_object)referencesacl_object_identity(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_2 foreign key(object_id_class)references acl_class(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_3 foreign key(owner_sid)references acl_sid(id) );</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">create table acl_entry (</span><br><span class="line"></span><br><span class="line">  id number not null primary key,</span><br><span class="line"></span><br><span class="line">  acl_object_identity number not null,ace_order int not null,sid number not null,</span><br><span class="line"></span><br><span class="line">  mask number(3) not null,granting number(1) not null,audit_success number(1) not null,</span><br><span class="line"></span><br><span class="line">  audit_failure number(1) not null,</span><br><span class="line"></span><br><span class="line">  constraint unique_uk_4 unique(acl_object_identity,ace_order),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_4 foreign key(acl_object_identity)</span><br><span class="line"></span><br><span class="line">      references acl_object_identity(id),</span><br><span class="line"></span><br><span class="line">  constraint foreign_fk_5 foreign key(sid) references acl_sid(id) );</span><br></pre></td></tr></table></figure>
<p>新增记录时用于生成主键的sequence定义为：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">  create or replace sequence seq_acl_sid start with 1 increment by 1;</span><br><span class="line"></span><br><span class="line">  create or replace sequence seq_acl_class start with 1 increment by 1;</span><br><span class="line"></span><br><span class="line">  create or replace sequence seq_acl_object_identity start with 1 increment by 1;</span><br><span class="line"></span><br><span class="line">  create or replace sequence seq_acl_entry start with 1 increment by 1;</span><br></pre></td></tr></table></figure></p>
<h2 id="1-2-表功能介绍"><a href="#1-2-表功能介绍" class="headerlink" title="1.2 表功能介绍"></a>1.2 表功能介绍</h2><p>如上所示，Spring Security的Acl功能需要使用到四张数据库表，分别为acl_sid、acl_class、acl_object_identity和acl_entry。</p>
<h3 id="1-2-1-表acl-sid"><a href="#1-2-1-表acl-sid" class="headerlink" title="1.2.1 表acl_sid"></a>1.2.1 表acl_sid</h3><p>表acl_sid的结构如下所示：<br>|字段名|类型|说明|<br>– | – | –<br>|id|number|主键|<br>|sid|varchar|字符串类型的sid|<br>|principal|boolean|是否用户|</p>
<p>表acl_sid是用来保存Sid的。对于Acl而言，有两种类型的Sid，一种是基于用户的Sid，叫PrincipalSid；另一种是基于GrantedAuthority的Sid，叫GrantedAuthoritySid。acl_sid表的sid字段存放的是用户名或者是GrantedAuthority的字符串表示。prinpal是用来区分对应的Sid是用户还是GrantedAuthority的。正如在前文所描述的那样，Acl中对象的权限是用来授予给Sid的，Sid有用户和GrantedAuthority之分，所以我们的对象权限是可以用来授予给用户或GrantedAuthority的。</p>
<h3 id="1-2-2-表acl-class"><a href="#1-2-2-表acl-class" class="headerlink" title="1.2.2 表acl_class"></a>1.2.2 表acl_class</h3><p>表acl_class的结构如下所示：</p>
<table>
<thead>
<tr>
<th></th>
<th>字段名</th>
<th>类型</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td>id</td>
<td>number</td>
<td>主键</td>
<td></td>
</tr>
<tr>
<td></td>
<td>class</td>
<td>varchar</td>
<td>对象类型的全限定名</td>
<td></td>
</tr>
</tbody>
</table>
<p>表acl_class是用来保存对象类型的，字段class中保存的是对应对象的全限定名。Acl需要使用它来区分不同的对象类型。</p>
<h3 id="1-2-3-表acl-object-identity"><a href="#1-2-3-表acl-object-identity" class="headerlink" title="1.2.3 表acl_object_identity"></a>1.2.3 表acl_object_identity</h3><p>表acl_object_identity的结构如下：<br>|字段名|类型|描述|<br>– | – | –<br>|id|number|主键|<br>|object_id_class|number|关联acl_class，表示对象类型|<br>|object_id_identity|number|对象的主键，对于相同的class而言，其需要是唯一的。对象的主键默认需要是Long型，或者可以转换为Long型的对象，如Integer、Short等。|<br>|parent_object|number|父对象的id，关联acl_object_identity|<br>|owner_sid|number|拥有者的sid，关联acl_sid|<br>|entries_inheriting|boolean|是否继承父对象的权限。打个比方，删除对象childObj需要有delete权限，用户A他没有childObj的delete权限，但是他有childObj的父对象parentObj的delete权限，当entries_inheriting为true时，用户A同样可以删除childObj。|</p>
<p>表acl_object_identity是用来存放需要进行访问控制的对象的信息的。其保存的信息有对象的拥有者、对象的类型、对象的主键、对象的父对象和是否继承父对象的权限。</p>
<h3 id="1-2-4-表acl-entry"><a href="#1-2-4-表acl-entry" class="headerlink" title="1.2.4 表acl_entry"></a>1.2.4 表acl_entry</h3><table>
<thead>
<tr>
<th></th>
<th>字段名</th>
<th>类型</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>id</td>
<td>number</td>
<td>主键</td>
<td></td>
</tr>
<tr>
<td>acl_object_identity</td>
<td>number</td>
<td>对应acl_object_identity的id</td>
<td></td>
</tr>
<tr>
<td>ace_order</td>
<td>number</td>
<td>所属Acl的权限顺序</td>
<td></td>
</tr>
<tr>
<td>sid</td>
<td>number</td>
<td>对应acl_sid的id</td>
<td></td>
</tr>
<tr>
<td>mask</td>
<td>number</td>
<td>权限对应的掩码</td>
<td></td>
</tr>
<tr>
<td>granting</td>
<td>boolean</td>
<td>是否授权</td>
<td></td>
</tr>
<tr>
<td>audit_success</td>
<td>boolean</td>
<td>暂未发现其作用，Acl中有一个更新其值的方法，但未见被调用。</td>
<td></td>
</tr>
<tr>
<td>audit_failure</td>
<td>boolean</td>
<td></td>
</tr>
</tbody>
</table>
<p>表acl_entry是用于存放具体的权限信息的，从表结构我们也可以看出来，其描述的就是某个主体（Sid）对某个对象（acl_object_identity）是否（granting）拥有某种权限（mask）。当同一对象acl_object_identity在acl_entry表中拥有多条记录时，就会使用ace_order来标记对应的顺序，其对应于往Acl中插入AccessControlEntry时的位置，在进行权限判断时也是依靠ace_order的顺序来进行的，ace_order越小的越先进行判断。ace是Access Control Entry的简称。</p>
<h2 id="1-3-Acl主要接口"><a href="#1-3-Acl主要接口" class="headerlink" title="1.3 Acl主要接口"></a>1.3 Acl主要接口</h2><p>对于Acl而言，有两块比较核心的功能，一块是往对应的数据库表里面插数据，另一块是从数据库表里面取出对应的数据进行权限鉴定。要了解这些功能我们先来了解Acl中用到的主要接口。</p>
<p><strong>Sid</strong>：可以用来表示一个principal，或者是一个GrantedAuthority。其对应的实现类有表示principal的PrincipalSid和表示GrantedAuthority的GrantedAuthoritySid。其信息会保存在acl_sid表中。</p>
<p><strong>ObjectIdentity</strong>：ObjectIdentity表示Spring Security Acl中一个域对象，其默认实现类是ObjectIdentityImpl。ObjectIdentity并不是直接与acl_object_identity表相对应的，真正与acl_object_identity表直接相对应的是Acl。</p>
<p><strong>Acl</strong>：每一个领域对象都会对应一个Acl，而且只会对应一个Acl。Acl是将Spring Security Acl中使用到的四个表串联起来的一个接口，其中会包含对象信息ObjectIdentity、对象的拥有者Sid和对象的访问控制信息AccessControlEntry。在Spring Security Acl中直接与acl_object_identity表相关联的是Acl接口，因为acl_object_identity表中的数据是通过保存Acl来进行的。一个Acl对应于一个ObjectIdentity，但是会包含有多个Sid和多个AccessControlEntry，即一个Acl表示所有Sid对一个ObjectIdentity的所有AccessControlEntry。Acl的默认实现类是AclImpl，该类实现Acl接口、MutableAcl接口、AuditableAcl接口和OwnershipAcl接口。</p>
<p><strong>AccessControlEntry</strong>：一个AccessControlEntry表示一条访问控制信息，一个Acl中可以拥有多个AccessControlEntry。在Spring Security Acl中很多地方会使用ACE来简单的表示AccessControlEntry这个概念，比如insertAce其实表示的就是insert AccessControlEntry。每一个AccessControlEntry表示对应的Sid对于对应的对象ObjectIdentity是否被授权某一项权限Permission，是否被授权将使用granting进行区分。AccessControlEntry对应表acl_entry。</p>
<p><strong>Permission</strong>：在Acl中使用一个bit掩码来表示一个Permission。Spring Security的Acl中默认使用的是BasePermission，其中已经定义了0-4五个bit掩码，分别对应于1、2、4、8、16，代表五种不同的Permission，分别是read (bit 0)、write (bit 1)、create (bit 2)、delete (bit 3)和administer (bit 4)。如果已经定义好的这五个bit掩码不能满足需求，我们可以对BasePermission进行扩展，也可以实现自己的Permission。Spring Security Acl默认的实现最多可以支持32个不同的掩码。</p>
<p><strong>AclService</strong>：AclService是用来通过ObjectIdentity解析Acl的，其默认实现类是JdbcAclService。JdbcAclService底层操作是通过LookupStrategy来进行的，LookupStrategy的默认实现是BasicLookupStrategy。</p>
<p><strong>MutableAclService</strong>：MutableAclService是用来对Acl进行持久化的，其默认实现类是JdbcMutableAclService。JdbcMutableAclService是继承自JdbcAclService的，所以我们可以同时通过JdbcMutableAclService对Acl进行读取和保存。如果我们希望自己来实现Acl信息的保存的话，我们也可以不使用该接口。</p>
<h2 id="1-4-配置AclService"><a href="#1-4-配置AclService" class="headerlink" title="1.4 配置AclService"></a>1.4 配置AclService</h2><p>AclService是使用Spring Security Acl功能的主入口。这里选择一个既可以从数据库读取Acl信息，又可以保存Acl信息到数据库的JdbcMutableAclService做示例。</p>
<p>JdbcMutableAclService只有一个构造方法，它接收三个参数，DataSource、LookupStrategy和AclCache。其对应配置信息如下所示：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;aclService&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.JdbcMutableAclService&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;lookupStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<p>配置JdbcMutableAclService有一点需要注意的地方，那就是其在与数据库进行交互的时候所基于的脚本是本文开始部分我们提到的那些脚本。其对应的数据库表的主键是自增的，所以在保存Acl时所给出的脚本中没有新增主键id。比如在新增sid时默认使用的脚本是“insert into acl_sid (principal, sid) values (?, ?)”，显然对于使用Oracle数据库作为示例的我们来说这条SQL是有问题的，因为新增的时候主键不能为空，所以如果我们需要使用JdbcMutableAclService来创建Acl的话我们得给JdbcMutableAclService指定新增记录时使用的脚本。这里我们将在新增的时候从之前建立好的Sequence获取值作为主键，示例如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;aclService&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.JdbcMutableAclService&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;lookupStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertSidSql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_sid(id, principal, sid) values (seq_acl_sid.nextval, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertClassSql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_class(id, class) values (seq_acl_class.nextval, ?)&quot;/&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertObjectIdentitySql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_object_identity(id, object_id_class, object_id_identity, owner_sid, entries_inheriting) values(seq_acl_object_identity.nextval, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertEntrySql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_entry(id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure) values (seq_acl_entry.nextval, ?, ?, ?, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<p>除了上述四个SQL之外，我们还需要指定两个属性对应的查询SQL，sidIdentityQuery和classIdentityQuery。因为JdbcMutableAclService在创建Acl时，如果当前用户在acl_sid表中不存在或当前对象类型在acl_class表中不存在，其会先将对应的信息存入acl_sid表和acl_class表，然后需要取出刚刚新增的acl_sid的主键和acl_class的主键以往acl_object_identity表中插入数据，对应acl_object_identity表中的owner_sid和object_id_class字段。这两个属性的默认值是“call identity()”，显然对于Oracle数据库来说这是行不通的，所以我们需要自己指定它们。这里我们通过对应Sequence的当前值来获取刚刚新增的记录的主键。如：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">  &lt;bean id=&quot;aclService&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.JdbcMutableAclService&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;lookupStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertSidSql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_sid(id, principal, sid) values (seq_acl_sid.nextval, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertClassSql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_class(id, class) values (seq_acl_class.nextval, ?)&quot;/&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertObjectIdentitySql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_object_identity(id, object_id_class, object_id_identity, owner_sid, entries_inheriting) values(seq_acl_object_identity.nextval, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertEntrySql&quot;</span><br><span class="line"></span><br><span class="line">  value=&quot;insert into acl_entry(id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure) values (seq_acl_entry.nextval, ?, ?, ?, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;sidIdentityQuery&quot; value=&quot;select seq_acl_sid.currval from dual&quot;/&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;classIdentityQuery&quot; value=&quot;select seq_acl_class.currval from dual&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<h3 id="1-4-1-配置DataSource"><a href="#1-4-1-配置DataSource" class="headerlink" title="1.4.1 配置DataSource"></a>1.4.1 配置DataSource</h3><p>配置数据源这个没什么好说的，大家都见惯了，为保持文章的完整性，我这里还是把它列一下。直接上代码：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">   &lt;context:property-placeholder location=&quot;/WEB-INF/config/jdbc.properties&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;dataSource&quot; class=&quot;org.apache.commons.dbcp2.BasicDataSource&quot;</span><br><span class="line"></span><br><span class="line">      destroy-method=&quot;close&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;driverClassName&quot; value=&quot;$&#123;jdbc.driverClassName&#125;&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;url&quot; value=&quot;$&#123;jdbc.url&#125;&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;username&quot; value=&quot;$&#123;jdbc.username&#125;&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;password&quot; value=&quot;$&#123;jdbc.password&#125;&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<h3 id="1-4-2-配置LookupStrategy"><a href="#1-4-2-配置LookupStrategy" class="headerlink" title="1.4.2 配置LookupStrategy"></a>1.4.2 配置LookupStrategy</h3><pre><code>LookupStrategy是用来通过ObjectIdentity解析为对应的Acl的。Spring Security Acl中的默认实现类是BasicLookupStrategy，其的构造需要接收四个参数。
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">   &lt;bean id=&quot;lookupStrategy&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.BasicLookupStrategy&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclAuthorizationStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;grantingStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<h3 id="1-4-3-配置AclAuthorizationStrategy"><a href="#1-4-3-配置AclAuthorizationStrategy" class="headerlink" title="1.4.3 配置AclAuthorizationStrategy"></a>1.4.3 配置AclAuthorizationStrategy</h3><pre><code>aclAuthorizationStrategy是在构造Acl的实现类AclImpl时必须给定的一个参数，其会用来在对Acl进行某些操作时检查当前用户是否具有对应的权限。AclAuthorizationStrategy的默认实现类是AclAuthorizationStrategyImpl，其构造需要接收一个或三个GrantedAuthority参数，用来对Acl进行相关操作时所需要的权限，包括更改Acl对应对象的所有者需要的权限、更改Acl中包含的某个AccessControlEntry的audit信息（对应acl_entry表中的is_audit_success和is_audit_failure字段）需要的权限以及其它如增、删、改Acl中所包含的AccessControlEntry等需要的权限。这些权限的鉴定是我们在操作Acl时由Spring Security Acl内部进行判断的，我们只需要在这里定义就好。当Acl对应的所有者对Acl进行操作时，不管其是否拥有指定需要的权限，除了改变audit信息之外的所有操作默认都是被允许的。当只有一个参数时表示三者共用一个GrantedAuthority。
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">  &lt;bean id=&quot;aclAuthorizationStrategy&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.domain.AclAuthorizationStrategyImpl&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;list&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;ROLE_ADMIN&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;gaModifyAuditing&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;gaGeneralChanges&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">  &lt;/list&gt;</span><br><span class="line"></span><br><span class="line">      &lt;/constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<h3 id="1-4-4-配置grantingStrategy"><a href="#1-4-4-配置grantingStrategy" class="headerlink" title="1.4.4 配置grantingStrategy"></a>1.4.4 配置grantingStrategy</h3><pre><code>grantingStrategy对应类型为PermissionGrantingStrategy接口，其中只定义了一个isGranted方法，用于判断基于指定的Permission列表和Sid列表指定的Acl是否被授予了访问权限。其默认实现类是DefaultPermissionGrantingStrategy。DefaultPermissionGrantingStrategy对于isGranted的实现逻辑是依次遍历Permission列表、Sid列表和Acl中包含的AccessControlEntry列表，找到第一个三者能够匹配的AccessControlEntry的isGranting（对应acl_entry表的granting字段）作为isGranted的返回结果。如果在当前Acl中没有找到匹配的AccessControlEntry，同时Acl对应的entriesInheriting为true时将继续使用父级的Acl进行匹配，并依次进行，如果都没有匹配到，则将抛出异常。
</code></pre><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;grantingStrategy&quot;</span><br><span class="line"></span><br><span class="line">   class=&quot;org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;bean class=&quot;org.springframework.security.acls.domain.ConsoleAuditLogger&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<h3 id="1-4-5-配置AclCache"><a href="#1-4-5-配置AclCache" class="headerlink" title="1.4.5 配置AclCache"></a>1.4.5 配置AclCache</h3><p>AclCache是用来缓存Acl信息的，Spring Security Acl中对于AclCache的默认实现是基于Ehcache的实现类EhCacheBasedAclCache。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;aclCache&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.domain.EhCacheBasedAclCache&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;cache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;grantingStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclAuthorizationStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;cache&quot; class=&quot;org.springframework.cache.ehcache.EhCacheFactoryBean&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheName&quot; value=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheManager&quot; ref=&quot;aclCacheManager&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;aclCacheManager&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.cache.ehcache.EhCacheManagerFactoryBean&quot;&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;configLocation&quot; value=&quot;/WEB-INF/config/ehcache.xml&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheManagerName&quot; value=&quot;aclCacheManager&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<p>为保持本文的完整性，这里贴出上述使用到的配置文件ehcache.xml的内容。具体如下所示：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">&lt;ehcache xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span><br><span class="line"></span><br><span class="line">   xsi:noNamespaceSchemaLocation=&quot;http://ehcache.org/ehcache.xsd&quot;</span><br><span class="line"></span><br><span class="line">   maxBytesLocalHeap=&quot;100M&quot;&gt;</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">   &lt;diskStore path=&quot;d:\\ehcache&quot; /&gt;</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">   &lt;defaultCache maxEntriesLocalHeap=&quot;200&quot; /&gt;</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">   &lt;cache name=&quot;aclCache&quot; maxBytesLocalHeap=&quot;50M&quot; maxBytesLocalDisk=&quot;5G&quot;</span><br><span class="line"></span><br><span class="line">      timeToIdleSeconds=&quot;120&quot; timeToLiveSeconds=&quot;600&quot; /&gt;</span><br><span class="line">&lt;/ehcache&gt;</span><br></pre></td></tr></table></figure>
<p>关于Ehcache的更多内容不在本文讨论范围之内，有需要的读者可以参考官方文档，也可以参考我的另一个关于Ehcache的系列文章。</p>
<p>至此，关于AclService配置的内容就讲完了，AclService配置的完整内容如下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br></pre></td><td class="code"><pre><span class="line">  &lt;bean id=&quot;aclService&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.JdbcMutableAclService&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;lookupStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertSidSql&quot;</span><br><span class="line">  value=&quot;insert into acl_sid(id, principal, sid) values (seq_acl_sid.nextval, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertClassSql&quot;</span><br><span class="line">  value=&quot;insert into acl_class(id, class) values (seq_acl_class.nextval, ?)&quot;/&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertObjectIdentitySql&quot;</span><br><span class="line">  value=&quot;insert into acl_object_identity(id, object_id_class, object_id_identity, owner_sid, entries_inheriting) values(seq_acl_object_identity.nextval, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;insertEntrySql&quot;</span><br><span class="line">  value=&quot;insert into acl_entry(id, acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure) values (seq_acl_entry.nextval, ?, ?, ?, ?, ?, ?, ?)&quot; /&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;sidIdentityQuery&quot; value=&quot;select seq_acl_sid.currval from dual&quot;/&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;classIdentityQuery&quot; value=&quot;select seq_acl_class.currval from dual&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;lookupStrategy&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.jdbc.BasicLookupStrategy&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;dataSource&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclAuthorizationStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;grantingStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;aclCache&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.domain.EhCacheBasedAclCache&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;cache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;grantingStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclAuthorizationStrategy&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;cache&quot; class=&quot;org.springframework.cache.ehcache.EhCacheFactoryBean&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheName&quot; value=&quot;aclCache&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheManager&quot; ref=&quot;aclCacheManager&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;aclCacheManager&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.cache.ehcache.EhCacheManagerFactoryBean&quot;&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;configLocation&quot; value=&quot;/WEB-INF/config/ehcache.xml&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;cacheManagerName&quot; value=&quot;aclCacheManager&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;aclAuthorizationStrategy&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.domain.AclAuthorizationStrategyImpl&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;list&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;ROLE_ADMIN&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;gaModifyAuditing&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;beanclass=&quot;org.springframework.security.core.authority.SimpleGrantedAuthority&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;constructor-arg value=&quot;gaGeneralChanges&quot; /&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">  &lt;/list&gt;</span><br><span class="line"></span><br><span class="line">      &lt;/constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;grantingStrategy&quot;</span><br><span class="line"></span><br><span class="line">   class=&quot;org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;bean class=&quot;org.springframework.security.acls.domain.ConsoleAuditLogger&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;/constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<h2 id="1-5-使用AclService"><a href="#1-5-使用AclService" class="headerlink" title="1.5 使用AclService"></a>1.5 使用AclService</h2><p>配置好AclService之后我们就可以使用该JdbcMutableAclService来创建、更新和查找Acl了。在Spring Security Acl中Acl接口的默认实现类是AclImpl，该类实现Acl接口、MutableAcl接口、AuditableAcl接口和OwnershipAcl接口，当有必要在这几种接口之间切换时可以任意切换。</p>
<h3 id="1-5-1-创建Acl"><a href="#1-5-1-创建Acl" class="headerlink" title="1.5.1 创建Acl"></a>1.5.1 创建Acl</h3><p>可以通过调用JdbcMutableAclService的createAcl()方法来创建一个Acl，其对应返回的是一个MutableAcl，该方法接收一个ObjectIdentity作为参数。在创建的时候如果ObjectIdentity对应的类型在acl_class表中不存在，则会把ObjectIdentity对应的类型添加到acl_class表中；如果当前用户对应的Sid在acl_sid表中不存在则会将其添加到acl_sid中。最后会将ObjectIdentity保存到acl_object_identity表中。正如在本文开始部分所描述的那样，一个Acl对应于一个ObjectIdentity，创建Acl就是创建ObjectIdentity的过程。在这三部分都完成之后，会重新从数据库查询出一个Acl，只是此时该Acl对应的AccessControlEntry列表为空。通常如果我们的对象是需要利用Acl进行访问控制的话，那么我们可以在创建该对象的时候一并创建该对象对应的Acl。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">   @Autowired</span><br><span class="line"></span><br><span class="line">   private MutableAclService aclService;</span><br><span class="line"></span><br><span class="line">   public void addUser(User user) &#123;</span><br><span class="line">     </span><br><span class="line">      //1、构建一个ObjectIdentity</span><br><span class="line"></span><br><span class="line">      ObjectIdentity oi = new ObjectIdentityImpl(User.class, user.getId());</span><br><span class="line"></span><br><span class="line">      //2、创建一个Acl、此时会如果对应的信息不存在会依次创建，如当前用户对应的Sid、ObjectIdentity对应于acl_class表中的类型</span><br><span class="line"></span><br><span class="line">      //最后是往acl_object_identity中插入对应的数据</span><br><span class="line"></span><br><span class="line">      MutableAcl acl = aclService.createAcl(oi);</span><br><span class="line"></span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>
<p>ObjectIdentityImpl拥有多个构造方法，具体可以参考Spring Security的API文档。</p>
<h3 id="1-5-2查找Acl"><a href="#1-5-2查找Acl" class="headerlink" title="1.5.2查找Acl"></a>1.5.2查找Acl</h3><p>通过AclService的系列readAclById()方法可以通过给定的ObjectIdentity查找对应的Acl。此外通过findChildren()方法可以查找指定ObjectIdentity的子ObjectIdentity。关于这些方法的具体信息可以参考Spring Security的API文档。以下是一个简单的示例。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br></pre></td></tr></table></figure></p>
<h3 id="1-5-3更新Acl"><a href="#1-5-3更新Acl" class="headerlink" title="1.5.3更新Acl"></a>1.5.3更新Acl</h3><pre><code>Acl的更新主要是对应AccessControlEntry的更新，即对AccessControlEntry的增、删、改；此外还包括对Acl对应的ObjectIdentity信息的变更，如更改所有者、父子关系等。
</code></pre><p>如下是一些更新Acl的示例，需要注意的是在调用MutableAclService的updateAcl()方法将对应信息同步到数据库之前，对Acl所做的所有修改都只是在内存中的。使用updateAcl()更新Acl信息到数据库时，其底层实现会先将数据库中所有对应的AccessControlEntry都删除，然后再将内存中的AccessControlEntry列表保存到数据库中。以下是其实现代码。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">public MutableAcl updateAcl(MutableAcl acl) throws NotFoundException &#123;</span><br><span class="line"></span><br><span class="line"> Assert._notNull_(acl.getId(), &quot;Object Identity doesn&apos;t provide an identifier&quot;);</span><br><span class="line"></span><br><span class="line"> // Delete this ACL&apos;s ACEs in the acl_entry table</span><br><span class="line"> deleteEntries(retrieveObjectIdentityPrimaryKey(acl.getObjectIdentity()));</span><br><span class="line"></span><br><span class="line"> // Create this ACL&apos;s ACEs in the acl_entry table</span><br><span class="line"> createEntries(acl);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> // Change the mutable columns in acl_object_identity</span><br><span class="line"></span><br><span class="line"> updateObjectIdentity(acl);</span><br><span class="line"> // Clear the cache, including children</span><br><span class="line"></span><br><span class="line"> clearCacheIncludingChildren(acl.getObjectIdentity());</span><br><span class="line"> // Retrieve the ACL via superclass (ensures cache registration, proper retrieval etc)</span><br><span class="line"> return (MutableAcl) super.readAclById(acl.getObjectIdentity());</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>
<h4 id="1-5-3-1添加AccessControlEntry"><a href="#1-5-3-1添加AccessControlEntry" class="headerlink" title="1.5.3.1添加AccessControlEntry"></a>1.5.3.1添加AccessControlEntry</h4><p>添加AccessControlEntry是通过MutableAcl的insertAce()方法进行的，该方法的定义如下所示：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">   /**</span><br><span class="line">    * @param atIndexLocation 添加的位置，对应于acl_entry表中的ace_order字段</span><br><span class="line">    * @param permission 对应的Permission</span><br><span class="line">    * @param sid 对应Sid</span><br><span class="line">    * @param granting 是否赋予</span><br><span class="line">    */</span><br><span class="line">    void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting)</span><br></pre></td></tr></table></figure></p>
<p>参数atIndexLocation对应的是需要插入的AccessControlEntry在Acl对应的AccessControlEntry列表（java.util.List类型）中的位置，对应于acl_entry表中ace_order，而一个Acl代表其对应ObjectIdentity的所有关联Sid关联的所有AccessControlEntry，这个ace_order是在这个范围内的order。以下是一个添加AccessControlEntry的示例：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">      MutableAcl acl = ...;</span><br><span class="line"></span><br><span class="line">      //基于principal的Sid</span><br><span class="line"></span><br><span class="line">      Sid sid = **new**PrincipalSid(SecurityContextHolder._getContext_().getAuthentication());</span><br><span class="line"></span><br><span class="line">      Permission p = BasePermission._ADMINISTRATION_;//管理员权限</span><br><span class="line"></span><br><span class="line">      //将当前Acl的管理员权限赋予给指定的Sid</span><br><span class="line"></span><br><span class="line">      acl.insertAce(acl.getEntries().size(), p, sid, **true**);   //添加AccessControlEntry到内存</span><br><span class="line"></span><br><span class="line">      //保存到数据库</span><br><span class="line"></span><br><span class="line">      acl = aclService.updateAcl(acl);</span><br></pre></td></tr></table></figure></p>
<p>上述的Sid，也可以是一个GrantedAuthoritySid，当把一个Acl的某Permission赋予给一个GrantedAuthoritySid时表示拥有该GrantedAuthority的用户都将拥有对应的Permission。如：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">      MutableAcl acl = ...;</span><br><span class="line">      //基于GrantedAuthority的Sid</span><br><span class="line"></span><br><span class="line">      Sid sid = **new** GrantedAuthoritySid(&quot;ROLE_ADMIN&quot;);</span><br><span class="line"></span><br><span class="line">      Permission p = BasePermission._ADMINISTRATION_;//管理员权限</span><br><span class="line"></span><br><span class="line">      //将当前Acl的管理员权限赋予给指定的Sid</span><br><span class="line"></span><br><span class="line">      acl.insertAce(acl.getEntries().size(), p, sid, **true**);   //添加AccessControlEntry到内存</span><br><span class="line"></span><br><span class="line">      //保存到数据库</span><br><span class="line"></span><br><span class="line">      acl = aclService.updateAcl(acl);</span><br></pre></td></tr></table></figure></p>
<h4 id="1-5-3-2删除AccessControlEntry"><a href="#1-5-3-2删除AccessControlEntry" class="headerlink" title="1.5.3.2删除AccessControlEntry"></a>1.5.3.2删除AccessControlEntry</h4><p>通过调用MutableAcl的deleteAce(int aceIndex)方法可以删除Acl中指定位置的AccessControlEntry，aceIndex是从0开始的，底层是使用的List的remove(int index)方法。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br><span class="line"></span><br><span class="line">   acl.deleteAce(0);//内存中删除第一个AccessControlEntry</span><br><span class="line"></span><br><span class="line">   aclService.updateAcl(acl);//同步到数据库</span><br></pre></td></tr></table></figure></p>
<h4 id="1-5-3-3-更新AccessControlEntry"><a href="#1-5-3-3-更新AccessControlEntry" class="headerlink" title="1.5.3.3 更新AccessControlEntry"></a>1.5.3.3 更新AccessControlEntry</h4><p>通过MutableAcl的updateAce()可以更新指定位置的AccessControlEntry的Permission。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br><span class="line"></span><br><span class="line">   acl.updateAce(0, BasePermission._CREATE_);//内存中更新第一个AccessControlEntry对应的Permission</span><br><span class="line"></span><br><span class="line">   aclService.updateAcl(acl);//同步到数据库</span><br></pre></td></tr></table></figure></p>
<h4 id="1-5-3-4-修改所有者"><a href="#1-5-3-4-修改所有者" class="headerlink" title="1.5.3.4 修改所有者"></a>1.5.3.4 修改所有者</h4><p>可以通过Acl的getOwner()方法获取Acl对应ObjectIdentity的拥有者Sid。通过MutableAcl的setOwner()方法可以在内存中更新对应Acl的拥有者。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br><span class="line"></span><br><span class="line">   acl.setOwner(**new** PrincipalSid(&quot;user&quot;));//内存中更改拥有者</span><br><span class="line"></span><br><span class="line">   aclService.updateAcl(acl);//同步到数据库</span><br></pre></td></tr></table></figure></p>
<h4 id="1-5-3-5-修改父Acl"><a href="#1-5-3-5-修改父Acl" class="headerlink" title="1.5.3.5 修改父Acl"></a>1.5.3.5 修改父Acl</h4><p>通过Acl的getParentAcl()方法可以获取到Acl对应ObjectIdentity对应的父ObjectIdentity对应的Acl。通过MutableAcl的setParent()方法可以在内存中修改Acl对应的父Acl，即修改Acl对应ObjectIdentity对应的父ObjectIdentity。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br><span class="line"></span><br><span class="line">   Acl newParent = ...;//以某种方式获取到Acl</span><br><span class="line"></span><br><span class="line">   acl.setParent(newParent);//内存中更改父Acl</span><br><span class="line"></span><br><span class="line">   aclService.updateAcl(acl);//同步到数据库</span><br></pre></td></tr></table></figure></p>
<h4 id="1-5-3-6-修改继承策略"><a href="#1-5-3-6-修改继承策略" class="headerlink" title="1.5.3.6 修改继承策略"></a>1.5.3.6 修改继承策略</h4><p>通过Acl的isEntriesInheriting()可以获取到当前Acl对应ObjectIdentity的继承策略，创建Acl时该值默认为true。通过MutableAcl的setEntriesInheriting()方法可以在内存中修改该Acl对应ObjectIdentity的继承策略。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity oi = **new** ObjectIdentityImpl(User.**class**, user.getId());</span><br><span class="line"></span><br><span class="line">   //获取ObjectIdentity对应的Acl</span><br><span class="line"></span><br><span class="line">   MutableAcl acl = (MutableAcl) aclService.readAclById(oi);</span><br><span class="line"></span><br><span class="line">   acl.setEntriesInheriting(**false**);//内存中修改为不从父Acl继承AccessControlEntry</span><br><span class="line"></span><br><span class="line">   aclService.updateAcl(acl);//同步到数据库</span><br></pre></td></tr></table></figure>
<h3 id="1-5-4-删除Acl"><a href="#1-5-4-删除Acl" class="headerlink" title="1.5.4 删除Acl"></a>1.5.4 删除Acl</h3><p>当我们删除对象的时候应该连同对应的Acl也一起删除。使用MutableAclService的deleteAcl(ObjectIdentity oi, boolean deleteChildren)方法可以删除指定ObjectIdentity对应的Acl，deleteChildren表示是否连同子ObjectIdentity对应的Acl也一起删除。deleteAcl将删除对应的ObjectIdentity，以及对应的AccessControlEntry，即其会删除acl_object_identity表和acl_entry表中与当前Acl对应的ObjectIdentity相关的记录。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">   ObjectIdentity objectIdentity = **new** ObjectIdentityImpl(User.**class**, id);</span><br><span class="line"></span><br><span class="line">   aclService.deleteAcl(objectIdentity, **true**);</span><br></pre></td></tr></table></figure>
<h2 id="1-6-注入到AclPermissionEvaluator"><a href="#1-6-注入到AclPermissionEvaluator" class="headerlink" title="1.6 注入到AclPermissionEvaluator"></a>1.6 注入到AclPermissionEvaluator</h2><p>AclPermissionEvaluator是PermissionEvaluator的一个实现类。在之前关于使用基于表达式的权限控制一文中有提到过，PermissionEvaluator是为表达式hasPermission提供支持的。此外，PermissionEvaluator还为标签accesscontrollist提供支持。本节将就使用AclPermissionEvaluator支持在方法上使用@PreAuthorize进行权限控制时使用表达式hasPermission做一个简单讲解。</p>
<p>AclPermissionEvaluator的构造需要接收一个AclService参数，在进行权限鉴定时其需要通过AclService获取到对应对象对应的Acl，然后判断该Acl中是否具有指定的Sid和指定的Permission。</p>
<p>对于方法使用hasPermission表达式进行权限鉴定时需要做两个事情，首先需要指定global-method-security的pre-post-annotations=”enabled”。其次需要手工定义DefaultMethodSecurityExpressionHandler并指定其permissionEvaluator为我们定义的AclPermissionEvaluator。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">   &lt;security:global-method-security pre-post-annotations=&quot;enabled&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;security:expression-handler ref=&quot;expressionHandler&quot;/&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/security:global-method-security&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;expressionHandler&quot;class=&quot;org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;permissionEvaluator&quot; ref=&quot;aclPermissionEvaluator&quot;/&gt;</span><br><span class="line"></span><br><span class="line">&lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">   &lt;bean id=&quot;aclPermissionEvaluator&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.AclPermissionEvaluator&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclService&quot; /&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<p>定义后之后我们就可以在方法上使用@PreAuthorize和hasPermission表达式了。关于PermissionEvaluator和hasPermission的更多介绍可以参考《基于表达式的权限控制》一文。hasPermission有两种用法，一种是直接传一个对象和对应需要的权限，如hasPermission(object,permission)；另一种是传对象的id、对应类型和需要的权限，如hasPermission(targetId,targetType,permission)。传入的Permission是Spring Security Acl中的Permission接口实现类，而不是Spring Security的GrantedAuthority。传入的permission参数可以是一个Permission对象或Permission对象数组，也可以是一个整数或字符串。当传入的permission是整数或字符串时将由AclPermissionEvaluator的PermissionFactory进行解析，AclPermissionEvaluator默认拥有的PermissionFactory是DefaultPermissionFactory，其会将整形或字符串类型的permission解析成对应的BasePermission。如前所述，BasePermission中定义了五个BasePermission，其对应的名称和掩码分别为：READ (1)、WRITE (2)、CREATE (4)、DELETE (8)和ADMINISTER (16)。当permission使用字符串时我们只能使用这五种字符串，不区分大小写，表示当前用户或其所拥有的GrantedAuthority必须拥有指定对象的指定Permission才允许访问。但是当使用掩码时我们可以使用1、2、4、8和16。</p>
<p>接下来将简单的介绍一个使用@PreAuthorize和hasPermission表达式在方法上进行权限控制的示例。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">   @PreAuthorize(&quot;hasPermission(#id, &apos;com.spring.security.entity.User&apos;, 1)&quot;)</span><br><span class="line"></span><br><span class="line">   **public** User find(**int** id) &#123;</span><br><span class="line"></span><br><span class="line">      User user = **new** User();</span><br><span class="line"></span><br><span class="line">      user.setId(id);</span><br><span class="line"></span><br><span class="line">      **return** user;</span><br><span class="line"></span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>
<p>上述配置即表示调用find方法查看指定id对应的User对象时必须拥有掩码为1对应的Permission才行，或者在继续策略为true时拥有指定id父对象掩码为1对应的Permission也行。这时哪怕你是该User对象的拥有者，或者你拥有ADMINISTER权限，如果你没有对应的READ权限，你也不能访问该方法。如果觉得这种实现不符合你的要求，你可以实现自己的PermissionGrantingStrategy，然后将实现类bean注入到BasicLookupStrategy和EhcacheBasedAclCache中，这样在判断一个用户是否具有指定Acl的指定Permission时就可以使用自己的逻辑了。</p>
<p>上面的定义如果改成permission参数直接使用对象，可以这样定义：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">   @PreAuthorize(&quot;hasPermission(#id, &apos;com.spring.security.entity.User&apos;, T(org.springframework.security.acls.domain.BasePermission).READ)&quot;)</span><br><span class="line"></span><br><span class="line">   **public** User find(**int** id) &#123;</span><br><span class="line"></span><br><span class="line">      User user = **new** User();</span><br><span class="line"></span><br><span class="line">      user.setId(id);</span><br><span class="line"></span><br><span class="line">      **return** user;</span><br><span class="line"></span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>
<p>当permission参数定义为一个Permission数组时，会根据顺序依次匹配当前用户在指定的Acl中是否拥有对应Permission的AccessControlEntry，如果拥有则以第一个匹配到的AccessControlEntry的granting属性作为判断结果，没有匹配到还可以根据继承策略决定是否利用父级Acl进行匹配，都没匹配到就会抛异常了。</p>
<p>默认使用的BasePermission中只定义了五种Permission，如果这不能满足你的要求，那么我们可以实现自己的Permission，然后把它们注册到DefaultPermissionFactory中，并手工将该DefaultPermissionFactory注入到AclPermissionEvaluator中。前文已经说过AclPermissionEvaluator中使用的PermissionFactory默认是DefaultPermissionFactory，DefaultPermissionFactory中默认只注册了BasePermission中对应的五种Permission。以下是一个扩展Permission的简单示例。</p>
<p>首先实现自己的Permission类，这里简单的定义一个自己的类，然后继承BasePermission类。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">**public ****class** BasePermissionExt **extends** BasePermission &#123;</span><br><span class="line"></span><br><span class="line">   /**</span><br><span class="line"></span><br><span class="line">    * serialVersionUID</span><br><span class="line"></span><br><span class="line">    */</span><br><span class="line"></span><br><span class="line">   **private ****static ****final ****long **_serialVersionUID_ = 1L;</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">   **public** BasePermissionExt(**int** mask) &#123;</span><br><span class="line"></span><br><span class="line">      **super**(mask);</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">  </span><br><span class="line"></span><br><span class="line">    **public** BasePermissionExt(**int** mask, **char** code) &#123;</span><br><span class="line"></span><br><span class="line"> **super**(mask, code);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>然后在DefaultPermissionFactory中注册基于我们自己实现的Permission对象，并将该DefaultPermissionFactory注入到AclPermissionEvaluator中。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;aclPermissionEvaluator&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.AclPermissionEvaluator&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclService&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      </span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;permissionFactory&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;beanclass=&quot;org.springframework.security.acls.domain.DefaultPermissionFactory&quot;&gt;</span><br><span class="line"></span><br><span class="line">     &lt;constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;map&gt;</span><br><span class="line"></span><br><span class="line">     &lt;entry key=&quot;READ&quot;&gt;</span><br><span class="line"></span><br><span class="line"> &lt;bean class=&quot;com.xxx.spring.security.BasePermissionExt&quot;&gt;</span><br><span class="line"></span><br><span class="line">    &lt;constructor-arg value=&quot;1&quot;/&gt;</span><br><span class="line"></span><br><span class="line"> &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/entry&gt;</span><br><span class="line"></span><br><span class="line">     &lt;entry key=&quot;WRITE&quot;&gt;</span><br><span class="line"></span><br><span class="line"> &lt;bean class=&quot;com.xxx.spring.security.BasePermissionExt&quot;&gt;</span><br><span class="line"></span><br><span class="line">    &lt;constructor-arg value=&quot;2&quot;/&gt;</span><br><span class="line"></span><br><span class="line"> &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/entry&gt;</span><br><span class="line"></span><br><span class="line">  &lt;/map&gt;</span><br><span class="line"></span><br><span class="line">     &lt;/constructor-arg&gt;</span><br><span class="line"></span><br><span class="line">  &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">      &lt;/property&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<p>此外，还可以将我们的BasePermissionExt改成如下这样：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">public class BasePermissionExt extends BasePermission &#123;</span><br><span class="line">   /**</span><br><span class="line">    * serialVersionUID</span><br><span class="line">    */</span><br><span class="line">    private static final long_serialVersionUID_ = 1L;</span><br><span class="line"></span><br><span class="line">    public static final Permission _READ_ = new BasePermissionExt(1 &lt;&lt; 0, &apos;R&apos;); // 1</span><br><span class="line"></span><br><span class="line">    public static final Permission _WRITE_ = new BasePermissionExt(1 &lt;&lt; 1, &apos;W&apos;); // 2</span><br><span class="line"></span><br><span class="line">    public static final Permission _CREATE_ = new BasePermissionExt(1 &lt;&lt; 2, &apos;C&apos;); // 4</span><br><span class="line"></span><br><span class="line">    public static final Permission _DELETE_ = new BasePermissionExt(1 &lt;&lt; 3, &apos;D&apos;); // 8</span><br><span class="line"></span><br><span class="line">    public static final Permission _ADMINISTRATION_ = new BasePermissionExt(1 &lt;&lt; 4, &apos;A&apos;); // 16</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"></span><br><span class="line">   public BasePermissionExt(int mask) &#123;</span><br><span class="line"></span><br><span class="line">      super(mask);</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">    public BasePermissionExt(int mask, char code) &#123;</span><br><span class="line"></span><br><span class="line">        super(mask, code);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>然后通过传入Class参数来构造DefaultPermissionFactory。这个时候会将对应Class中所有类型为Permission的字段分别以字段名和字段值Permission对应的掩码为Key，以字段值Permission为Value进行注册。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">   &lt;bean id=&quot;aclPermissionEvaluator&quot;</span><br><span class="line"></span><br><span class="line">      class=&quot;org.springframework.security.acls.AclPermissionEvaluator&quot;&gt;</span><br><span class="line"></span><br><span class="line">      &lt;constructor-arg ref=&quot;aclService&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;property name=&quot;permissionFactory&quot;&gt;</span><br><span class="line"></span><br><span class="line">          &lt;beanclass=&quot;org.springframework.security.acls.domain.DefaultPermissionFactory&quot;&gt;</span><br><span class="line">        </span><br><span class="line">             &lt;constructor-arg value=&quot;com.spring.security.BasePermissionExt&quot;/&gt;</span><br><span class="line">        </span><br><span class="line">          &lt;/bean&gt;</span><br><span class="line"></span><br><span class="line">      &lt;/property&gt;</span><br><span class="line"></span><br><span class="line">   &lt;/bean&gt;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>（注：本文是基于Spring Security3.1.6所写）<br>（注：原创文章，转载请注明出处。原文地址：<a href="https://elim.iteye.com/blog/2269021" target="_blank" rel="noopener">http://elim.iteye.com/blog/2269021</a>）</p>
</blockquote>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://www.youngboy.vip/2018/12/23/Spring Security ACL/" data-id="cjq0rskqi000060nyirk2lzef" class="article-share-link">Share</a>
      
      
    </footer>
  </div>
  
</article>


  
    <article id="post-activiti" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="./2018/12/23/activiti/" class="article-date">
  <time datetime="2018-12-23T10:48:46.666Z" itemprop="datePublished">2018-12-23</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="基础流程"><a href="#基础流程" class="headerlink" title="基础流程"></a>基础流程</h2><h4 id="报错流程"><a href="#报错流程" class="headerlink" title="报错流程"></a>报错流程</h4><p><strong>自动检测</strong><br>检测设备的数值，自动报错给负责人，负责人处理后由巡查人员确认是否修好</p>
<p><strong>定期检测（是否允许重复报错？）</strong><br>人工巡查扫描二维码记录巡查记录，发现损坏的设备后巡查人员扫描二维码后app弹出设备的详情页面，详情页面上有设备报错按钮，点击按钮跳到对应的表单页面填写表单上报给设备负责人</p>
<p><strong>负责人报错</strong><br>负责人接到任务后，到达现场app扫描设备的二维码弹出设备详情，设备详情页面包含异常记录，和相对应的任务，点击某个任务进入表单填写页面选择故障设备部件名称，选择故障原因，选择处理的方式，如果选择的是报废处理就需要显示相关配件的库存，如果库存不够负责人需要发起申请采购流程等待采购流程完成，如果库存足够需要去仓库领取相关配件，仓库人员需要发起出库流程开取相关单据审批后才允许配件出库，设备修好后由巡查人员确认是否修好</p>
<p><strong>巡检人员复检</strong><br>巡检人员检查设备是否修好</p>
<h4 id="申请采购流程"><a href="#申请采购流程" class="headerlink" title="申请采购流程"></a>申请采购流程</h4><p>物料需求部门（负责人）在新品申购上发起物料采购流程<br>采购人员根据<code>《物料采购申请单》</code>进行采购<br>采购完物品后需向供应单位索取正规单具（名称、数量、金额，签字或盖章）</p>
<h4 id="入库流程"><a href="#入库流程" class="headerlink" title="入库流程"></a>入库流程</h4><p>采购人员采购完毕后，需将采购物品交仓库进行入库，仓库人员对采购物品验收后进行入库并开具<code>《入库单》</code></p>
<h4 id="出库流程"><a href="#出库流程" class="headerlink" title="出库流程"></a>出库流程</h4><p>仓库人员填写出库单，交给相关负责人审批，审批后出库</p>
<h4 id="报销流程"><a href="#报销流程" class="headerlink" title="报销流程"></a>报销流程</h4><p>采购人员持采购前审批的《物料采购申请单》，仓库开具的《入库单》和供应单位所开单具，到财务处申请报销，财务人员应认真核对数量及金额，并填写<code>领款凭证</code><br>送交总经理签字审批后，才能予以报销。</p>
<h4 id="经费申请流程"><a href="#经费申请流程" class="headerlink" title="经费申请流程"></a>经费申请流程</h4><p>填写经费申请单-&gt;领导审批-&gt;财务部门审批-&gt;总经理审批-&gt;出纳处领款</p>
<h4 id="检修计划审批流程"><a href="#检修计划审批流程" class="headerlink" title="检修计划审批流程"></a>检修计划审批流程</h4><p>发起人填写检修计划表单，相关负责人审批后发布</p>
<h2 id="Activiti-BPM平台"><a href="#Activiti-BPM平台" class="headerlink" title="Activiti BPM平台"></a>Activiti BPM平台</h2><ul>
<li>宏天EIP <a href="http://www.hotent.xyz:8093/login" target="_blank" rel="noopener">http://www.hotent.xyz:8093/login</a></li>
<li>红讯 <a href="http://www.redxun.cn:8020/saweb/login.jsp" target="_blank" rel="noopener">http://www.redxun.cn:8020/saweb/login.jsp   admin  1</a></li>
<li>agilebpm（开源） <a href="http://test.agilebpm.cn/login.html" target="_blank" rel="noopener">http://test.agilebpm.cn/login.html admin 1</a></li>
</ul>
<p>宏天EIP各个流程功能比较齐全，表单设计部分是拖拽式的设计，支持pc端表单和手机端表单，前台为anaglar单应用网页</p>
<p>红讯平台表单设计器使用富文本编辑器实现，支持pc端表单和手机端表单，流程设计操作有些复杂</p>
<p>agilebpm 功能与宏天EIP有部分类似，功能还算齐全，流程设计器UI做的比较粗糙，表单设计器使用富文本编辑器实现，支持pc端表单和手机端表单</p>
<table>
<thead>
<tr>
<th>平台</th>
<th>权限转移</th>
<th>流程干预</th>
<th>沟通与抄送</th>
<th>流程授权</th>
<th>表单字段授权</th>
<th>任务转办</th>
<th>任务代理</th>
</tr>
</thead>
<tbody>
<tr>
<td>宏天EIP</td>
<td>有</td>
<td>有</td>
<td>有</td>
<td>有</td>
<td>有</td>
<td>有</td>
<td>有</td>
</tr>
<tr>
<td>红讯</td>
<td>无</td>
<td>有</td>
<td>有</td>
<td>有</td>
<td>有</td>
<td>有</td>
<td>有</td>
</tr>
<tr>
<td>agilebpm</td>
<td>无</td>
<td>有</td>
<td>无</td>
<td>有</td>
<td>有</td>
<td>无</td>
<td>无</td>
</tr>
</tbody>
</table>
<h2 id="目标"><a href="#目标" class="headerlink" title="目标"></a>目标</h2><p>简洁的配置流程和表单，有效的流程监控和干预，快速实现业务流程</p>
<h2 id="主要功能模块"><a href="#主要功能模块" class="headerlink" title="主要功能模块"></a>主要功能模块</h2><ul>
<li>组织架构模块</li>
<li>业务建模模块</li>
<li>表单模块</li>
<li>流程模块</li>
</ul>
<h3 id="组织架构模块"><a href="#组织架构模块" class="headerlink" title="组织架构模块"></a>组织架构模块</h3><p>提供组织架构信息</p>
<h3 id="业务建模模块"><a href="#业务建模模块" class="headerlink" title="业务建模模块"></a>业务建模模块</h3><p>提供业务数据保存、更新、表定义、业务对象定义、表字段控件定义等功能</p>
<h3 id="表单模块"><a href="#表单模块" class="headerlink" title="表单模块"></a>表单模块</h3><p>提供表单的生成、表单高级控件的配置、表单对于业务数据增删改查的实现</p>
<h3 id="流程模块"><a href="#流程模块" class="headerlink" title="流程模块"></a>流程模块</h3><p>拓展activiti的功能</p>
<h2 id="主要功能实现"><a href="#主要功能实现" class="headerlink" title="主要功能实现"></a>主要功能实现</h2><ul>
<li>流程监控<ul>
<li>流程干预</li>
<li>权限转移</li>
<li>流转过程</li>
</ul>
</li>
<li>流程应用<ul>
<li>同意</li>
<li>驳回</li>
<li>沟通</li>
<li>保存</li>
<li>终止</li>
<li>抄送</li>
<li>反对</li>
<li>转办</li>
<li>流转</li>
<li>打印</li>
<li>撤回</li>
<li>延期</li>
<li>流程授权</li>
<li>表单字段授权</li>
</ul>
</li>
<li>业务建模<ul>
<li>实体管理</li>
<li>业务对象</li>
<li>生成物理表</li>
<li>外部表映射</li>
</ul>
</li>
<li>流程视图<ul>
<li>发起流程</li>
<li>代表任务</li>
<li>已办任务</li>
<li>办结流程</li>
<li>转办代理</li>
<li>代办预警</li>
<li>沟通与抄送</li>
</ul>
</li>
</ul>
<h2 id="一般使用流程"><a href="#一般使用流程" class="headerlink" title="一般使用流程"></a>一般使用流程</h2><p>业务建模 —&gt; 设计表单 —&gt; 设计流程 —&gt; 配置流程 -<br>—&gt; 发布流程 —&gt; 使用流程</p>
<h2 id="重点功能"><a href="#重点功能" class="headerlink" title="重点功能"></a>重点功能</h2><h3 id="业务建模"><a href="#业务建模" class="headerlink" title="业务建模"></a>业务建模</h3><h4 id="业务实体"><a href="#业务实体" class="headerlink" title="业务实体"></a>业务实体</h4><p>业务实体对应数据库中的表或数据，用户可以选择生成物理表或以json格式存在数据库中</p>
<h4 id="业务对象"><a href="#业务对象" class="headerlink" title="业务对象"></a>业务对象</h4><p>业务实体可能会关联其他表，所以业务对象是用来管理业务实体之间的关系的对象，设计表单时会用到业务对象</p>
<h3 id="表单设计器"><a href="#表单设计器" class="headerlink" title="表单设计器"></a>表单设计器</h3><h4 id="表单模板"><a href="#表单模板" class="headerlink" title="表单模板"></a>表单模板</h4><p>生成表单的模板使用freemark或其他模板引擎实现</p>
<h4 id="自定义对话框配置"><a href="#自定义对话框配置" class="headerlink" title="自定义对话框配置"></a>自定义对话框配置</h4><p>表单处理过程中与用户交互的对话框，如选择职务或选择用户等功能</p>
<h4 id="表单设计"><a href="#表单设计" class="headerlink" title="表单设计"></a>表单设计</h4><p>使用富文本编辑器输出内容为html，有些平台可以拖拽生成表单输出的数据为json</p>
<h3 id="流程设计器"><a href="#流程设计器" class="headerlink" title="流程设计器"></a>流程设计器</h3><p>拖拽生成流程，配置流程</p>
<h2 id="可配置项"><a href="#可配置项" class="headerlink" title="可配置项"></a>可配置项</h2><blockquote>
<p>脚本均为Groovy脚本</p>
</blockquote>
<h3 id="组织结构配置"><a href="#组织结构配置" class="headerlink" title="组织结构配置"></a>组织结构配置</h3><p>提供接口整合自己系统的组织架构</p>
<h3 id="流程权限控制"><a href="#流程权限控制" class="headerlink" title="流程权限控制"></a>流程权限控制</h3><p>把流程授权给指定的用户或组，只有授权的用户才可以启动流程</p>
<h3 id="常用脚本配置"><a href="#常用脚本配置" class="headerlink" title="常用脚本配置"></a>常用脚本配置</h3><p>脚本可以访问spring容器中的对象或引用静态类的方法，同时也可以访问流程变量</p>
<h3 id="流程配置项"><a href="#流程配置项" class="headerlink" title="流程配置项"></a>流程配置项</h3><h4 id="表单配置"><a href="#表单配置" class="headerlink" title="表单配置"></a>表单配置</h4><ul>
<li>全局表单<ul>
<li>手机表单</li>
<li>pc表单</li>
</ul>
</li>
<li>局部表单<ul>
<li>手机表单</li>
<li>pc表单</li>
</ul>
</li>
</ul>
<h4 id="表单字段授权"><a href="#表单字段授权" class="headerlink" title="表单字段授权"></a>表单字段授权</h4><p>指定表单中字段的修改(w)和只读(r)权限</p>
<h4 id="表单处理按钮配置"><a href="#表单处理按钮配置" class="headerlink" title="表单处理按钮配置"></a>表单处理按钮配置</h4><p>流程处理过程中显示的按钮，可以在流程设计的时候定义，按钮的属性和动作由后台配置</p>
<h4 id="流程节点事件配置（使用Groovy脚本配置）"><a href="#流程节点事件配置（使用Groovy脚本配置）" class="headerlink" title="流程节点事件配置（使用Groovy脚本配置）"></a>流程节点事件配置（使用Groovy脚本配置）</h4><ul>
<li>前置事件</li>
<li>后置事件</li>
</ul>
<h4 id="开始结束节点事件配置（使用Groovy脚本配置）"><a href="#开始结束节点事件配置（使用Groovy脚本配置）" class="headerlink" title="开始结束节点事件配置（使用Groovy脚本配置）"></a>开始结束节点事件配置（使用Groovy脚本配置）</h4><ul>
<li>开始事件</li>
<li>结束时间</li>
<li>人工终止事件</li>
</ul>
<h4 id="流程节点跳转规则配置"><a href="#流程节点跳转规则配置" class="headerlink" title="流程节点跳转规则配置"></a>流程节点跳转规则配置</h4><ul>
<li>手动选择某一个节点</li>
<li>使用脚本选择</li>
</ul>
<h4 id="人员配置"><a href="#人员配置" class="headerlink" title="人员配置"></a>人员配置</h4><ul>
<li>手动选择组织结构的一个维度</li>
<li>通过脚本配置</li>
<li>流程历史审批人</li>
<li>系统节点执行人</li>
</ul>
<h4 id="节点类型配置（单实例或多实例）"><a href="#节点类型配置（单实例或多实例）" class="headerlink" title="节点类型配置（单实例或多实例）"></a>节点类型配置（单实例或多实例）</h4><h4 id="流程通知配置"><a href="#流程通知配置" class="headerlink" title="流程通知配置"></a>流程通知配置</h4><p>流程结束开始或有任务时通知用户，有多种通知方式配置</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://www.youngboy.vip/2018/12/23/activiti/" data-id="cjq0rskqq000160ny0ackpc2w" class="article-share-link">Share</a>
      
      
    </footer>
  </div>
  
</article>


  
    <article id="post-hello-world" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="./2018/12/23/hello-world/" class="article-date">
  <time datetime="2018-12-23T10:48:46.666Z" itemprop="datePublished">2018-12-23</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="./2018/12/23/hello-world/">Hello World</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>Welcome to <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="noopener">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="noopener">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="noopener">GitHub</a>.</p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="noopener">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="noopener">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="noopener">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="noopener">Deployment</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://www.youngboy.vip/2018/12/23/hello-world/" data-id="cjq0rskqu000260nyam2kgtjq" class="article-share-link">Share</a>
      
      
    </footer>
  </div>
  
</article>


  
    <article id="post-test5" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="./2018/12/23/test5/" class="article-date">
  <time datetime="2018-12-23T10:48:46.666Z" itemprop="datePublished">2018-12-23</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>test md</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://www.youngboy.vip/2018/12/23/test5/" data-id="cjq0rskqx000360nysonzgkak" class="article-share-link">Share</a>
      
      
    </footer>
  </div>
  
</article>


  


</section>
        
          <aside id="sidebar">
  
    

  
    

  
    
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="./archives/2018/12/">December 2018</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="./2018/12/23/Spring Security ACL/">Spring Security ACL</a>
          </li>
        
          <li>
            <a href="./2018/12/23/activiti/">(no title)</a>
          </li>
        
          <li>
            <a href="./2018/12/23/hello-world/">Hello World</a>
          </li>
        
          <li>
            <a href="./2018/12/23/test5/">(no title)</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2018 youngboy<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="./" class="mobile-nav-link">Home</a>
  
    <a href="./archives" class="mobile-nav-link">Archives</a>
  
</nav>
    

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>


  <link rel="stylesheet" href="./fancybox/jquery.fancybox.css">
  <script src="./fancybox/jquery.fancybox.pack.js"></script>


<script src="./js/script.js"></script>



  </div>
</body>
</html>